using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using ZoneFiveSoftware.Common.Data.Fitness;
using System.Reflection;

namespace FilteredStatistics.Common.Controller
{
    class ProxyFilterCriteria : FilterCriteriaFacade
    {
        public ProxyFilterCriteria(object criteria)
        {
            if (criteria == null)
            {
                throw new Exception("Invalid filter criteria pointer");
            }

            Type criteriaType = criteria.GetType();

            m_FilterCriteriaObject = criteria;

            m_ReferenceIdProperty = criteriaType.GetProperty("ReferenceId", typeof(Guid));
            m_DisplayNameProperty = criteriaType.GetProperty("DisplayName", typeof(String));
            m_ActivityProperty = criteriaType.GetProperty("Activity", typeof(IActivity));
            m_NamedZonesProperty = criteriaType.GetProperty("NamedZones", typeof(List<object>));
            m_IsTemplateOnlyProperty = criteriaType.GetProperty("IsTemplateOnly", typeof(bool));
            m_IsMainViewOnlyProperty = criteriaType.GetProperty("IsMainViewOnly", typeof(bool));
            m_IsSerializableProperty = criteriaType.GetProperty("IsSerializable", typeof(bool));
            m_DataVersionProperty = criteriaType.GetProperty("DataVersion", typeof(UInt16));
            m_TemplateCompatibleCriteriaProperty = criteriaType.GetProperty("TemplateCompatibleCriteria", typeof(object));
            m_SerializeCriteriaMethod = criteriaType.GetMethod("SerializeCriteria", new Type[] { typeof(Stream) });
            m_DeserializeCriteriaMethod = criteriaType.GetMethod("DeserializeCriteria", new Type[] { typeof(Stream), typeof(UInt16) });
            m_OnSelectedInListMethod = criteriaType.GetMethod("OnSelectedInList", new Type[] { typeof(object) });
            m_ValidateConsistencyMethod = criteriaType.GetMethod("ValidateConsistency", new Type[] { typeof(bool) });
            m_NamedZonesChangedEvent = criteriaType.GetEvent("NamedZonedListChanged");

            if (m_ReferenceIdProperty == null ||
                !m_ReferenceIdProperty.CanRead ||
                m_DisplayNameProperty == null ||
                !m_DisplayNameProperty.CanRead ||
                m_ActivityProperty == null ||
                !m_ActivityProperty.CanWrite ||
                m_NamedZonesProperty == null ||
                !m_NamedZonesProperty.CanRead ||
                m_IsTemplateOnlyProperty == null ||
                !m_IsTemplateOnlyProperty.CanRead ||
                m_IsMainViewOnlyProperty == null ||
                !m_IsMainViewOnlyProperty.CanRead ||
                m_IsSerializableProperty == null ||
                !m_IsSerializableProperty.CanRead ||
                m_DataVersionProperty == null ||
                !m_DataVersionProperty.CanRead ||
                m_SerializeCriteriaMethod == null ||
                m_SerializeCriteriaMethod.ReturnType != typeof(void) ||
                m_DeserializeCriteriaMethod == null ||
                m_DeserializeCriteriaMethod.ReturnType != typeof(object) ||
                m_NamedZonesChangedEvent == null)
            {
                throw new Exception("Filter criteria doesn't implement IFilterCriteria interface");
            }

            // Make sure our optional functions are valid
            if (m_TemplateCompatibleCriteriaProperty != null &&
                !m_TemplateCompatibleCriteriaProperty.CanRead)
            {
                m_TemplateCompatibleCriteriaProperty = null;
            }

            if (m_OnSelectedInListMethod != null &&
                m_OnSelectedInListMethod.ReturnType != typeof(object))
            {
                m_OnSelectedInListMethod = null;
            }

            if (m_ValidateConsistencyMethod != null &&
                m_ValidateConsistencyMethod.ReturnType != typeof(bool))
            {
                m_ValidateConsistencyMethod = null;
            }

            m_NamedZonesChangedEvent.AddEventHandler(m_FilterCriteriaObject, Delegate.CreateDelegate(typeof(PropertyChangedEventHandler), this, "NamedZonesChangedEventHandler"));

            TriggerNamedZonesListChanged();
        }

#region FilterCriteriaFacade

        public override Guid ReferenceId
        {
            get { return (Guid)m_ReferenceIdProperty.GetValue(m_FilterCriteriaObject, null); }
        }

        public override IActivity Activity
        {
            set { m_ActivityProperty.SetValue(m_FilterCriteriaObject, value, null); }
        }

        public override String DisplayName
        {
            get { return m_DisplayNameProperty.GetValue(m_FilterCriteriaObject, null) as String; }
        }
        
        public override List<object> NamedZones
        {
            get { return m_NamedZonesProperty.GetValue(m_FilterCriteriaObject, null) as List<object>; }
        }

        public override bool IsTemplateOnly
        {
            get { return (bool)m_IsTemplateOnlyProperty.GetValue(m_FilterCriteriaObject, null); }
        }

        public override bool IsMainViewOnly
        {
            get { return (bool)m_IsMainViewOnlyProperty.GetValue(m_FilterCriteriaObject, null); }
        }

        public override bool IsSerializable
        {
            get { return (bool)m_IsSerializableProperty.GetValue(m_FilterCriteriaObject, null); }
        }

        public override void SerializeCriteria(Stream stream)
        {
            m_SerializeCriteriaMethod.Invoke(m_FilterCriteriaObject, new object[] { stream });
        }

        public override UInt16 DataVersion
        {
            get { return (UInt16)m_DataVersionProperty.GetValue(m_FilterCriteriaObject, null); }
        }

        public override object DeserializeCriteria(Stream stream, ushort version)
        {
            return m_DeserializeCriteriaMethod.Invoke(m_FilterCriteriaObject, new object[] { stream, version });
        }

        public override object OnSelectedInList(object previousSelection)
        {
            if (m_OnSelectedInListMethod != null)
            {
                object concretePreviousSelection = previousSelection;

                if (previousSelection is ProxyFilterCriteria)
                {
                    concretePreviousSelection = (previousSelection as ProxyFilterCriteria).m_FilterCriteriaObject;
                }

                return m_OnSelectedInListMethod.Invoke(m_FilterCriteriaObject, new object[] { concretePreviousSelection });
            }

            return base.OnSelectedInList(previousSelection);
        }

        public override object TemplateCompatibleCriteria
        {
            get
            {
                if (m_TemplateCompatibleCriteriaProperty != null)
                {
                    return m_TemplateCompatibleCriteriaProperty.GetValue(m_FilterCriteriaObject, null);
                }

                return base.TemplateCompatibleCriteria;
            }
        }

        public override bool ValidateConsistency()
        {
            if (m_ValidateConsistencyMethod != null)
            {
                return (bool)m_ValidateConsistencyMethod.Invoke(m_FilterCriteriaObject, new object[] { });
            }

            return base.ValidateConsistency();
        }

#endregion

        private void NamedZonesChangedEventHandler(object sender, PropertyChangedEventArgs e)
        {
            TriggerNamedZonesListChanged();
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            object obj2 = obj;

            if (obj is ProxyFilterCriteria)
            {
                obj2 = (obj as ProxyFilterCriteria).m_FilterCriteriaObject;
            }

            return m_FilterCriteriaObject.Equals(obj2);
        }

        private object m_FilterCriteriaObject = null;
        private PropertyInfo m_ReferenceIdProperty = null;
        private PropertyInfo m_DisplayNameProperty = null;
        private PropertyInfo m_ActivityProperty = null;
        private PropertyInfo m_NamedZonesProperty = null;
        private PropertyInfo m_IsTemplateOnlyProperty = null;
        private PropertyInfo m_IsMainViewOnlyProperty = null;
        private PropertyInfo m_IsSerializableProperty = null;
        private PropertyInfo m_DataVersionProperty = null;
        private PropertyInfo m_TemplateCompatibleCriteriaProperty = null;
        private MethodInfo m_SerializeCriteriaMethod = null;
        private MethodInfo m_DeserializeCriteriaMethod = null;
        private MethodInfo m_OnSelectedInListMethod = null;
        private MethodInfo m_ValidateConsistencyMethod = null;
        private EventInfo m_NamedZonesChangedEvent = null;
    }
}
